from robyn import SubRouter

from middleware.auth_middleware import auth_required
from models.database import SessionLocal
from models.do.user_do import UserModel
from models.do.role_do import RoleModel
from models.do.user_role_do import UserRoleModel
from utils.jwt_util import create_access_token, create_refresh_token, verify_refresh_token
from services import user_service
from constants import HttpStatus
from utils.password_util import verify_or_compare_password, decrypt_username, encrypt_username, hash_or_store_password
from utils.id_util import generate_id
from utils.error_handler import get_error_response, handle_database_error
from datetime import datetime

auth_controller = SubRouter(__file__, prefix="/api/auth")

@auth_controller.post("/login")
async def login(request):
    credentials = request.json()
    username = credentials.get("username")
    password = credentials.get("password")

    if not username or not password:
        return {
            "code": HttpStatus.BAD_REQUEST,
            "msg": "Username and password are required",
            "data": None
        }

    with SessionLocal() as db:
        user = db.query(UserModel).filter(UserModel.username == encrypt_username(username)).first()

        if not user or not verify_or_compare_password(password, user.hashed_password):
            return {
                "code": HttpStatus.UNAUTHORIZED,
                "msg": "Invalid credentials",
                "data": None
            }

        # In a real application, you would fetch user roles here
        # For now, let's assume a simple role based on is_superuser
        roles = ["admin"] if user.is_superuser else ["user"]
        
        token_data = {
            "user_id": user.id,
            "roles": roles,
            "user_info": {
                "id": user.id,
                "username": decrypt_username(user.username),
                "is_superuser": user.is_superuser,
                "login_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            }
        }

        access_token = create_access_token(data=token_data)
        refresh_token = create_refresh_token(data={"user_id": user.id})
        
        return {
            "code": HttpStatus.OK,
            "msg": "Login successful",
            "data": {
                "access_token": access_token,
                "refresh_token": refresh_token,
                "token_type": "bearer"
            }
        }

@auth_controller.post("/refresh")
async def refresh(request):
    token_data = request.json()
    refresh_token = token_data.get("refresh_token")

    if not refresh_token:
        return {
            "code": HttpStatus.BAD_REQUEST,
            "msg": "Refresh token is required",
            "data": None
        }

    payload = verify_refresh_token(refresh_token)
    if not payload:
        return {
            "code": HttpStatus.UNAUTHORIZED,
            "msg": "Invalid or expired refresh token",
            "data": None
        }

    user_id = payload.get("user_id")
    user = user_service.getUser(user_id)

    if not user:
        return {
            "code": HttpStatus.UNAUTHORIZED,
            "msg": "User not found",
            "data": None
        }

    # Create a new access token
    token_data = {
        "user_id": user['id'],
        "roles": [role['name'] for role in user.get('roles', [])],
        "user_info": {
            "id": user['id'],
            "username": user['username'],
            "is_superuser": user['isSuperuser'],
            "login_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        }
    }
    new_access_token = create_access_token(data=token_data)

    return {
        "code": HttpStatus.OK,
        "msg": "Token refreshed successfully",
        "data": {
            "access_token": new_access_token,
            "token_type": "bearer"
        }
    }


@auth_controller.post("/register")
async def register(request):
    user_data = request.json()
    username = user_data.get("username")
    password = user_data.get("password")
    
    if not username or not password:
        return {
            "code": HttpStatus.BAD_REQUEST,
            "msg": "Username and password are required",
            "data": None
        }
    
    # Validate username length
    if len(username) < 3 or len(username) > 50:
        return {
            "code": HttpStatus.BAD_REQUEST,
            "msg": "Username must be between 3 and 50 characters",
            "data": None
        }
    
    # Validate password strength
    if len(password) < 6:
        return {
            "code": HttpStatus.BAD_REQUEST,
            "msg": "Password must be at least 6 characters long",
            "data": None
        }
    
    with SessionLocal() as db:
        # Check if username already exists
        encrypted_username = encrypt_username(username)
        existing_user = db.query(UserModel).filter(UserModel.username == encrypted_username).first()
        
        if existing_user:
            return {
                "code": HttpStatus.BAD_REQUEST,
                "msg": "Username already exists",
                "data": None
            }
        
        # Create new user
        try:
            new_user = UserModel(
                id=generate_id(),
                username=encrypted_username,
                hashed_password=hash_or_store_password(password),
                is_active=True,
                is_superuser=False
            )
            
            db.add(new_user)
            db.commit()
            db.refresh(new_user)
            
            return {
                "code": HttpStatus.CREATED,
                "msg": "User registered successfully",
                "data": {
                    "id": new_user.id,
                    "username": username,
                    "is_active": new_user.is_active
                }
            }
        except Exception as e:
            db.rollback()
            # 在调试模式下返回详细的错误信息，包括基本错误信息
            error_response = handle_database_error(e, "user registration")
            # 确保基本错误信息始终可见
            if "error_info" not in error_response:
                error_response["error_info"] = {
                    "error_type": type(e).__name__,
                    "error_message": str(e)
                }
            return error_response


@auth_controller.post("/assign-role")
@auth_required()
async def assign_role(request):
    role_data = request.json()
    user_id = role_data.get("user_id")
    role_name = role_data.get("role_name")
    
    if not user_id or not role_name:
        return {
            "code": HttpStatus.BAD_REQUEST,
            "msg": "User ID and role name are required",
            "data": None
        }
    
    with SessionLocal() as db:
        try:
            # Check if user exists
            user = db.query(UserModel).filter(UserModel.id == user_id).first()
            if not user:
                return {
                    "code": HttpStatus.NOT_FOUND,
                    "msg": "User not found",
                    "data": None
                }
            
            # Check if role exists
            role = db.query(RoleModel).filter(RoleModel.name == role_name).first()
            if not role:
                return {
                    "code": HttpStatus.NOT_FOUND,
                    "msg": f"Role '{role_name}' not found",
                    "data": None
                }
            
            # Check if user already has this role
            existing_user_role = db.query(UserRoleModel).filter(
                UserRoleModel.user_id == user_id,
                UserRoleModel.role_id == role.id
            ).first()
            
            if existing_user_role:
                return {
                    "code": HttpStatus.BAD_REQUEST,
                    "msg": f"User already has the role '{role_name}'",
                    "data": None
                }
            
            # Assign role to user
            new_user_role = UserRoleModel(
                user_id=user_id,
                role_id=role.id
            )
            
            db.add(new_user_role)
            db.commit()
            
            return {
                "code": HttpStatus.OK,
                "msg": f"Role '{role_name}' assigned to user successfully",
                "data": {
                    "user_id": user_id,
                    "role_name": role_name,
                    "role_id": role.id
                }
            }
            
        except Exception as e:
            db.rollback()
            # 在调试模式下返回详细的错误信息，包括基本错误信息
            error_response = handle_database_error(e, "role assignment")
            # 确保基本错误信息始终可见
            if "error_info" not in error_response:
                error_response["error_info"] = {
                    "error_type": type(e).__name__,
                    "error_message": str(e)
                }
            return error_response


@auth_controller.delete("/remove-role")
@auth_required()
async def remove_role(request):
    role_data = request.json()
    user_id = role_data.get("user_id")
    role_name = role_data.get("role_name")
    
    if not user_id or not role_name:
        return {
            "code": HttpStatus.BAD_REQUEST,
            "msg": "User ID and role name are required",
            "data": None
        }
    
    with SessionLocal() as db:
        try:
            # Check if user exists
            user = db.query(UserModel).filter(UserModel.id == user_id).first()
            if not user:
                return {
                    "code": HttpStatus.NOT_FOUND,
                    "msg": "User not found",
                    "data": None
                }
            
            # Check if role exists
            role = db.query(RoleModel).filter(RoleModel.name == role_name).first()
            if not role:
                return {
                    "code": HttpStatus.NOT_FOUND,
                    "msg": f"Role '{role_name}' not found",
                    "data": None
                }
            
            # Find the user-role relationship
            user_role = db.query(UserRoleModel).filter(
                UserRoleModel.user_id == user_id,
                UserRoleModel.role_id == role.id
            ).first()
            
            if not user_role:
                return {
                    "code": HttpStatus.BAD_REQUEST,
                    "msg": f"User does not have the role '{role_name}'",
                    "data": None
                }
            
            # Remove role from user
            db.delete(user_role)
            db.commit()
            
            return {
                "code": HttpStatus.OK,
                "msg": f"Role '{role_name}' removed from user successfully",
                "data": {
                    "user_id": user_id,
                    "role_name": role_name,
                    "role_id": role.id
                }
            }
            
        except Exception as e:
            db.rollback()
            # 在调试模式下返回详细的错误信息，包括基本错误信息
            error_response = handle_database_error(e, "role removal")
            # 确保基本错误信息始终可见
            if "error_info" not in error_response:
                error_response["error_info"] = {
                    "error_type": type(e).__name__,
                    "error_message": str(e)
                }
            return error_response


@auth_controller.delete("/delete-user")
async def delete_user(request):
    user_data = request.json()
    user_id = user_data.get("user_id")
    
    if not user_id:
        return {
            "code": HttpStatus.BAD_REQUEST,
            "msg": "User ID is required",
            "data": None
        }
    
    with SessionLocal() as db:
        try:
            # Check if user exists
            user = db.query(UserModel).filter(UserModel.id == user_id).first()
            if not user:
                return {
                    "code": HttpStatus.NOT_FOUND,
                    "msg": "User not found",
                    "data": None
                }
            
            # Get username for response (before deletion)
            username = decrypt_username(user.username)
            
            # Delete all user roles first (due to foreign key constraints)
            db.query(UserRoleModel).filter(UserRoleModel.user_id == user_id).delete()
            
            # Delete the user
            db.delete(user)
            db.commit()
            
            return {
                "code": HttpStatus.OK,
                "msg": "User and associated roles deleted successfully",
                "data": {
                    "user_id": user_id,
                    "username": username,
                    "deleted_at": datetime.now().isoformat()
                }
            }
            
        except Exception as e:
            db.rollback()
            # 在调试模式下返回详细的错误信息，包括基本错误信息
            error_response = handle_database_error(e, "user deletion")
            # 确保基本错误信息始终可见
            if "error_info" not in error_response:
                error_response["error_info"] = {
                    "error_type": type(e).__name__,
                    "error_message": str(e)
                }
            return error_response


@auth_controller.get("/codes")
async def codes(request):
        try:
            return {
                "code": HttpStatus.OK,
                "msg": "get successfully",
                "data": [

                ]
            }

        except Exception as e:
            # 在调试模式下返回详细的错误信息，包括基本错误信息
            error_response = handle_database_error(e, "codes")
            # 确保基本错误信息始终可见
            if "error_info" not in error_response:
                error_response["error_info"] = {
                    "error_type": type(e).__name__,
                    "error_message": str(e)
                }
            return error_response